# -*- coding: iso-8859-1 -*-
#
#    This is part of Malvinas Argentinas Messenger
#
#    Malvinas Argentinas Messenger is free software; you can redistribute
#    it and/or modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; either version 2 of the
#    License, or (at your option) any later version.
#
#    Malvinas Argentinas Messenger is distributed in the hope that it will be
#    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Malvinas Argentinas Messenger; if not, write to the Free
#    Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
#    MA  02110-1301  USA

# This would not have been completed without emesene p2p code.
# Primarily taken from there, and modified for Malvinas Argentinas Messenger.

import struct

class ByteArray(object):
	'''a class that represent a byte array (little endian)'''
	def __init__(self, size):
		'''create a byte array with size=size and initialize with 0'''
		self.fmt = '<' + str(size) + 'B'
		self.data = struct.pack(self.fmt, *[0 for i in range(size)])
		self.valueList = list(struct.unpack(self.fmt, self.data))
		
	def getData(self):
		return self.data

	def __setitem__(self, pos, value):
		'''set the value in pos'''
		if len(self.valueList) > pos:
			self.valueList[pos] = value
			self.data = struct.pack(self.fmt, *self.valueList)
	
	def __getitem__(self, pos):
		return self.valueList[pos]

	def setDword(self, pos, value):
		# less significative
		byte1 = self.__extractByte(value, 0)
		byte2 = self.__extractByte(value, 1)
		byte3 = self.__extractByte(value, 2)
		byte4 = self.__extractByte(value, 3)
		self[pos] = byte1
		self[pos+1] = byte2
		self[pos+2] = byte3
		self[pos+3] = byte4
	
	def getDword(self, pos):
		byte1 = self[pos]
		byte2 = self[pos+1]
		byte3 = self[pos+2]
		byte4 = self[pos+3]
		return (byte4<<24) + (byte3<<16) + (byte2<<8) + byte1

	def setQword(self, pos, value):
		byte1 = self.__extractByte(value, 0)
		byte2 = self.__extractByte(value, 1)
		byte3 = self.__extractByte(value, 2)
		byte4 = self.__extractByte(value, 3)
		byte5 = self.__extractByte(value, 4)
		byte6 = self.__extractByte(value, 5)
		byte7 = self.__extractByte(value, 6)
		byte8 = self.__extractByte(value, 7)
		self[pos] = byte1
		self[pos+1] = byte2
		self[pos+2] = byte3
		self[pos+3] = byte4
		self[pos+4] = byte5
		self[pos+5] = byte6
		self[pos+6] = byte7
		self[pos+7] = byte8

	def getQword(self, start):
		return (self.getDword(start + 4) << 32) + self.getDword(start)

	def __extractByte(self, number, byte):
		'''
		extract a given byte of a number and return it
		0 -> first byte ( less significative )
		'''
		return (number & (255 << byte * 8)) >> (byte * 8)
	
	def __repr__(self):
		return self.data

	def __len__(self):
		return len(self.valueList)

	def getDwordFromData(self, header, start):
		'''extract 4 bytes from header starting from start
		and return it as a number'''
		b1 = ord(header[start])
		b2 = ord(header[start+1])
		b3 = ord(header[start+2])
		b4 = ord(header[start+3])
		return (b4<<24) + (b3<<16) + (b2<<8) + b1
	
	def getQwordFromData(self, header, start):
		# i think its like this
		return (self.getDwordFromData(header, start + 4) << 32) + self.getDwordFromData(header, start)

class BinHeader(ByteArray):
	'''this class represent the bin header'''
	def __init__(self, data = None):
		'''Contructor'''
		ByteArray.__init__(self, 48)
		if data != None:
			self.fill(data)

	def setSessionID(self, dword):
		self.setDword(0, dword)

	def getSessionID(self):
		return self.getDword(0)

	def setIdentifier(self, dword):
		self.setDword(4, dword)

	def getIdentifier(self):
		return self.getDword(4)

	def setDataOffset(self, qword):
		self.setQword(8, qword)

	def getDataOffset(self):
		return self.getQword(8)

	def setTotalDataSize(self, qword):
		self.setQword(16, qword)

	def getTotalDataSize(self):
		return self.getQword(16)

	def setMessageLength(self, dword):
		self.setDword(24, dword)

	def getMessageLength(self):
		return self.getDword(24)

	def setFlag(self, dword):
		self.setDword(28, dword)

	def getFlag(self):
		return self.getDword(28)

	def setAcknowledgedIdentifier(self, dword):
		self.setDword(32, dword)
	
	def getAcknowledgedIdentifier(self):
		return self.getDword(32)

	def setAcknowledgedUniqueID(self, dword):
		self.setDword(36, dword)

	def getAcknowledgedUniqueID(self):
		return self.getDword(36)

	def setAcknowledgedDataSize(self, qword):
		self.setQword(40, qword)

	def getAcknowledgedDataSize(self):
		return self.getQword(40)

	def printNumbers(self):
		count = 0
		for i in self.data:
			print hex(ord(i)),
			if len(str(hex(ord(i)))) == 3:
				print '  ',
			else:
				print ' ',
			count += 1
			if count > 15:
				print
				count = 0
		print

	def printFields(self):
		#a = '-------------------------------------------\n'
		a = '\tSessionID:               ' + str(self.getSessionID()) + '\n'
		a += '\tIdentifier:              ' + str(self.getIdentifier()) + '\n'
		a += '\tData offset:             ' + str(self.getDataOffset()) + '\n'
		a += '\tTotal data size:         ' + str(self.getTotalDataSize()) + '\n'
		a += '\tMessage length:          ' + str(self.getMessageLength()) + '\n'
		a += '\tFlag:                    ' + str(self.getFlag()) + '\n'
		a += '\tAcknowledged identifier: ' + str(self.getAcknowledgedIdentifier()) + '\n'
		a += '\tAcknowledged unique ID:  ' + str(self.getAcknowledgedUniqueID()) + '\n'
		a += '\tAcknowledged data size:  ' + str(self.getAcknowledgedDataSize())
		#a += '-------------------------------------------\n'
		return a

	def fill(self, data):
		self.setSessionID(self.getDwordFromData(data, 0))
		self.setIdentifier(self.getDwordFromData(data, 4))
		self.setDataOffset(self.getQwordFromData(data, 8))
		self.setTotalDataSize(self.getQwordFromData(data, 16))
		self.setMessageLength(self.getDwordFromData(data, 24))
		self.setFlag(self.getDwordFromData(data, 28))
		self.setAcknowledgedIdentifier(self.getDwordFromData(data, 32))
		self.setAcknowledgedUniqueID(self.getDwordFromData(data, 36))
		self.setAcknowledgedDataSize(self.getQwordFromData(data, 40))
